package com.ledim.chat;

import android.os.Handler;
import com.ledim.bean.LedimChatMsgBean;
import com.ledim.bean.LedimJoinAckBean;
import com.ledim.bean.LedimJoinBean;
import com.ledim.bean.LedimKickOffBean;
import com.ledim.bean.LedimRoomUsersInfoBean;
import com.ledim.chat.model.ChatEntity;
import com.ledim.chat.model.BaseSocketMessage;
import com.ledim.chat.model.MessageHeader;
import com.ledim.service.coverter.LedimGsonConverterFactory;
import com.ledim.utils.LedimSpUtils;
import com.ledim.utils.LogUtil;
import java.io.IOException;
import org.json.JSONException;

public class ConnectionManager {

    public static final String TAG = "ledimchat";
    /** 最大重连次数 **/
    private static final int MAX_RECONNECT_COUNT = 100;
    /** 心跳时间 **/
    private static final int HEART_BEAT = 60 * 1000;
    /** 重连delay时间 **/
    private static final int RECONNECT_DELAY = 12 * 1000;
    /** 心跳管理 **/
    private ConnectActiveMonitor mMonitor;
    /** 接收消息线程 **/
    private ReceiverThread mReceiverThread;
    /** socket链接 **/
    private ConnectThread mConnectThread;
    /** socket连接 **/
    private SocketConnection mSocketConnection;
    /** 是否加入聊天室成功 **/
    private volatile boolean isJoined;
    /** 回调 **/
    private ChatCallback mCallback;
    private Handler mHandler;
    /** 服务器地址 **/
    private String mServer;
    /** 房间号 **/
    private String mRoomID;
    /** token **/
    private String mToken;
    /** 重连次数 **/
    private int mReConnectCount;
    private String mtVkey;
    private boolean mNeedReTryIfFailed;

    public ConnectionManager(ChatCallback callback) {
        this.mCallback = callback;
        this.mHandler = new Handler();
    }

    /**
     * 连接
     */
    public void connect(String server, String roomID) {
        LogUtil.e(TAG, "连接connect");
        mReConnectCount++;
        if (mReConnectCount > MAX_RECONNECT_COUNT) {
            return;
        }

        this.mServer = server;
        this.mRoomID = roomID;
        this.mToken = "";
        LogUtil.e(TAG, "SOCKET连接");
        if (mSocketConnection == null) {
            mSocketConnection = new SocketConnection();
        }
        if (mMonitor != null) {
            mMonitor.stopRunning();
        }
        mMonitor = new ConnectActiveMonitor();

        if (mReceiverThread != null) {
            mReceiverThread.stopRunning();
        }
        mReceiverThread = new ReceiverThread();

        if (mConnectThread != null) {
            mConnectThread.stopRunning();
        }
        mConnectThread = new ConnectThread();

        mConnectThread.starRuning(server, roomID);
    }

    private byte[] getJoinMessage(String roomId, String token) {

        LedimJoinBean join = new LedimJoinBean();
        join.roomId = Integer.valueOf(roomId);

        if (LedimSpUtils.isLogin()) {
            join.uid = Integer.parseInt(LedimSpUtils.getLetvId());
            LogUtil.e("ccx login chat uid=" + join.uid + ",room id" + roomId);
            join.subUserNum = 1;
        } else {
            join.uid = 0;
            join.subUserNum = 0;
        }

        join.cType = 3;
        join.token = token;
        join.cVersion = "1.0";
        join.groupMode = 0;
        String body = null;
        try {
            body = join.toJson().toString();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        LogUtil.e(TAG, "send comd join data=" + body);
        return BaseSocketMessage.getStructMessage(MessageHeader.CMD_JOIN, 0, 0, 0, 0, 0, 0, body);
    }

    /**
     * 加入房间
     */
    public void joinRoom(String roomID, String token) {
        LogUtil.e(TAG, "加入房间joinRoom");
        if (mSocketConnection != null && mSocketConnection.isConnect()) {
            try {
                //启动心跳和消息接收线程
                if (mMonitor != null) {
                    mMonitor.startRunning();
                }
                if (mReceiverThread != null) {
                    mReceiverThread.startRunning();
                }

                mSocketConnection.sendMessage(getJoinMessage(roomID, token));
            } catch (IOException e) {
            }
        }
    }

    /**
     * 判断是否连接
     *
     * @return
     */
    public boolean isConnect() {
        if (mSocketConnection != null) {
            return mSocketConnection.isConnect();
        }
        return false;
    }

    /**
     * 关闭
     */
    public void close() {
        LogUtil.e(TAG, "close");
        mReConnectCount = 0;
        mtVkey = null;

        if (mConnectThread != null) {
            mConnectThread.interrupt();
            mConnectThread = null;
        }
        if (mMonitor != null) {
            mMonitor.stopRunning();
            mMonitor = null;
        }
        if (mReceiverThread != null) {
            mReceiverThread.stopRunning();
            mReceiverThread = null;
        }
        if (mSocketConnection != null) {
            mSocketConnection.close();
        }
    }

    /**
     * 回传消息
     */
    private void callbackMessage(final ChatEntity chat) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mCallback != null) {
                    mCallback.onReceiveMessage(chat);
                }
            }
        });
    }

    /**
     * 接收消息线程
     */
    private class ReceiverThread extends Thread {

        private boolean isRunning;

        @Override
        public void run() {
            while (isRunning && mSocketConnection != null) {
                BaseSocketMessage message = null;
                if ((message = mSocketConnection.readMessage()) != null && message.header != null) {
                    LogUtil.e(TAG, "收到新的消息 message=" + message + ",message.header.cmd=" +
                            message.header.cmd);
                    Object data = null;
                    switch (message.header.cmd) {
                        case MessageHeader.CMD_JOIN_ACK:
                            LogUtil.e(TAG, "加入聊天室成功 message=" + message.body);
                            //加入聊天室成功
                            LedimJoinAckBean body =
                                    LedimGsonConverterFactory.create().gson.fromJson(message.body, LedimJoinAckBean.class);
                            if (body != null && body.code == 0) {
                                isJoined = true;
                                mtVkey = body.vtkey;
                                data = body;
                            }
                            break;
                        case MessageHeader.CMD_ROOM_MSG:
                            LogUtil.e("ccx msg MessageHeader.CMD_ROOM_MSG=" + message.body);
                            data =
                                    LedimGsonConverterFactory.create().gson.fromJson(message.body, LedimChatMsgBean.class)
                                                                           .getRealChatMsgBean();
                            break;
                        case MessageHeader.CMD_ROOM_USERNUMBER:
                            data =
                                    LedimGsonConverterFactory.create().gson.fromJson(message.body, LedimRoomUsersInfoBean.class);
                            break;
                        case MessageHeader.CMD_USER_KICKOFF:
                        case MessageHeader.CMD_USER_SILENT:
                        case MessageHeader.CMD_USER_UNSILENT:
                            // 用户被踢出,被禁言,解除禁言
                            data =
                                    LedimGsonConverterFactory.create().gson.fromJson(message.body, LedimKickOffBean.class);
                            break;
                    }
                    if (data != null) {
                        callbackMessage(new ChatEntity(data, message.header.cmd));
                    }

                }
            }

        }

        public void stopRunning() {
            isRunning = false;
            interrupt();
        }

        public void startRunning() {
            isRunning = true;
            if (getState() == State.NEW) {
                super.start();
            }
        }
    }

    /**
     * socket连接
     */
    private class ConnectThread extends Thread {

        private String server;
        private String roomID;
        private String token;
        private boolean isRunning;

        public void starRuning(String server, String roomID) {
            if (getState() != State.NEW) {
                return;
            }

            this.isRunning = true;
            this.server = server;
            this.roomID = roomID;
            this.token = "";
            super.start();
        }

        public void stopRunning() {
            isRunning = false;
        }

        @Override
        public void run() {
            if (mSocketConnection != null) {
                mSocketConnection.setServer(server);
                mSocketConnection.connect();

                if (!mSocketConnection.isConnect() && mNeedReTryIfFailed) {
                    mNeedReTryIfFailed = false;
                    connect(mServer, mRoomID);
                    return;
                }

                if (isRunning) {
                    //加入房间
                    joinRoom(roomID, token);
                }
            }
        }
    }

    /**
     * 心跳管理器
     */
    private class ConnectActiveMonitor extends Thread {

        private volatile boolean isRuning;
        private byte[] messaage;

        public ConnectActiveMonitor() {
            this.messaage =
                    BaseSocketMessage.getStructMessage(MessageHeader.CMD_PING, 0, 0, 0, 0, 0, 0, null);
        }

        @Override
        public void run() {
            LogUtil.e(TAG, "启动心跳线程");
            while (isRuning) {
                try {
                    LogUtil.e(TAG, "每分钟一次心跳");
                    Thread.sleep(HEART_BEAT);

                    if (mSocketConnection == null) {
                        isRuning = false;
                        break;
                    }

                    if (!mSocketConnection.isConnect() || !isJoined) {
                        //等待连接
                        continue;
                    }

                    if (mSocketConnection.getLastBeatTime() + HEART_BEAT <=
                            System.currentTimeMillis()) {
                        mSocketConnection.setLastBeatTime(System.currentTimeMillis());

                        mSocketConnection.sendMessage(messaage);
                    }
                } catch (InterruptedException e) {
                    LogUtil.e(TAG, "心跳线程断开");
                    isRuning = false;
                } catch (IOException e) {
                    LogUtil.e(TAG, "心跳连接失败，重新连接服务器 延迟重连");
                    //重连
                    mHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mNeedReTryIfFailed = true;
                            connect(mServer, mRoomID);
                        }
                    }, RECONNECT_DELAY);

                }
            }
        }

        public void stopRunning() {
            isRuning = false;
            interrupt();
        }

        public void startRunning() {
            isRuning = true;
            if (getState() == State.NEW) {
                super.start();
            }
        }
    }

    /**
     * 获取vtkey
     *
     * @return
     */
    public String getVtKey() {
        return mtVkey;
    }

    /**
     * 设置vkey
     *
     * @param vkey
     * @return
     */
    public void setVkey(String vkey) {
        this.mtVkey = vkey;
    }
}
